home *** CD-ROM | disk | FTP | other *** search
- //////////////////////////////////////////////////////////////////////////
- // TabDlg 3.0
- // Copyright (c) 1994 Edward McCreary.
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms are freely permitted
- // provided that the above copyright notice and attibution and date of work
- // and this paragraph are duplicated in all such forms.
- // THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
- // IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- // WARRANTIES OF MERCHANTIBILILTY AND FITNESS FOR A PARTICULAR PURPOSE.
- ///////////////////////////////////////////////////////////////////////////
- // File: tabdlg3.c
- // Author: Ed McCreary
- // Date: 11/7/94
- // Purpose: custom control to implement Word 6.0 style tabs
- ///////////////////////////////////////////////////////////////////////////
- #define STRICT
- #include <windows.h>
- #include <windowsx.h>
- #include <stdlib.h>
- #include <string.h>
- #include "tabdlg3.h"
- #include "internal.h"
-
-
- // global variables
-
- // instance handle of this module
- HINSTANCE hInstance = NULL;
-
- // font to used for depressed tabs
- HFONT hDepressedFont = NULL;
-
- // predefined class names for merging dialog box templates
- static char *szPredefinedClassNames[] =
- { "BUTTON", "EDIT", "STATIC",
- "LISTBOX", "SCROLLBAR", "COMBOBOX" };
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: LibMain
- // Purpose: main entry point for library
- // Parameters: hInst - instance handle of library
- // wDataSeg - library data segment
- // wHeapSize default heap size
- // lpszCmdLine command-line arguments
- //
- // Returns: TRUE on success
- // FALSE on failure
- ///////////////////////////////////////////////////////////////////////////
- BOOL WINAPI LibMain (HINSTANCE hInst, WORD wDataSeg,
- WORD wHeapSize, LPSTR lpszCmdLine)
- {
- if(wHeapSize != 0)
- UnlockData(0);
-
- // store off dll instance handle
- hInstance = hInst;
-
- // to keep the compiler from bitching
- wDataSeg = wDataSeg;
- lpszCmdLine = lpszCmdLine;
-
- // init tab library
- if(!TabControlInit())
- {
- TabControlExit();
- return FALSE;
- }
-
- return TRUE;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: WEP
- // Purpose: windows exit procuedure
- // Parameters: nSystemExit exit code
- //
- // Returns: 1
- ///////////////////////////////////////////////////////////////////////////
- int WINAPI WEP(int nSystemExit)
- {
- // cleanup after tab
- TabControlExit();
- return 1;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: TabControlInit
- // Purpose: registers tab control class with Windows
- // Parameters: none
- //
- // Returns: TRUE on success
- // FALSE on failure
- ///////////////////////////////////////////////////////////////////////////
- BOOL WINAPI __export TabControlInit(void)
- {
- WNDCLASS wc;
- LOGFONT logfont;
- HDC hdc;
-
- // fill in class style
- wc.style = TAB_CLASS;
- wc.lpfnWndProc = TabDlgWndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = CBWNDEXTRA;
- wc.hInstance = hInstance;
- wc.hIcon = NULL;
- wc.hCursor = LoadCursor(NULL,IDC_ARROW);
- wc.hbrBackground = NULL;
- wc.lpszMenuName = NULL;
- wc.lpszClassName = TAB_CLASSNAME;
-
- if (!RegisterClass(&wc)) // register class
- return FALSE; // abort if failed
-
- hdc = GetDC(NULL);
- // create font used to draw depressed tab titles
- // logfont.lfWeight = FW_THIN;
- // 10 point height Sans Serif font (8 point for Win4)
- memset(&logfont,0,sizeof(logfont));
- logfont.lfWeight = FW_NORMAL;
- logfont.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
- logfont.lfHeight = -MulDiv(8, GetDeviceCaps(hdc,LOGPIXELSY), 72);
- lstrcpy(logfont.lfFaceName, "MS Sans Serif");
-
- ReleaseDC(NULL,hdc);
- // bang
- hDepressedFont = CreateFontIndirect(&logfont);
-
- return TRUE; // return success
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: TabControlExit
- // Purpose: unregisters tab class with windows
- // Parameters: none
- //
- // Returns: n/a
- ///////////////////////////////////////////////////////////////////////////
- void WINAPI __export TabControlExit(void)
- {
- // unregister class with windows
- UnregisterClass(TAB_CLASSNAME,hInstance);
-
- // destroy font object if needed
- if(hDepressedFont)
- DeleteObject(hDepressedFont);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: TabDlgWndProc
- // Purpose: main callback for tab control
- // Parameters: hWnd - window handle
- // uMsg - message
- // wParam - word size parameter
- // lParam - dword size parameter
- //
- // Returns: msg dependent
- ///////////////////////////////////////////////////////////////////////////
- LRESULT WINAPI __export TabDlgWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- LPTABCTLBLK pData = NULL;
- LRESULT dwReturn;
-
- // get pointer to memory block used to store tab information
- // this is create during WM_NCCREATE
- if(uMsg != WM_NCCREATE)
- pData = (LPTABCTLBLK)GlobalLock((HGLOBAL)GetWindowWord(hWnd,GWW_DATA));
-
- switch(uMsg)
- {
- case WM_NCCREATE:
- dwReturn = OnNCCreate(hWnd, (CREATESTRUCT FAR *)lParam);
- break;
-
- case WM_NCDESTROY:
- dwReturn = OnNCDestroy(pData);
- break;
-
- case WM_CREATE:
- {
- // make sure window has transparent style bit on
- LONG lStyle;
-
- lStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
- lStyle |= WS_EX_TRANSPARENT;
- SetWindowLong(hWnd,GWL_EXSTYLE, lStyle);
-
- dwReturn = DefWindowProc(hWnd,uMsg,wParam,lParam);
- }
- break;
-
- case WM_KEYDOWN:
- switch(wParam)
- {
- // rotate tab one left
- case VK_LEFT:
- if(pData->pActiveTab && pData->pActiveTab->prev)
- dwReturn = SendMessage(hWnd,TAB_SETCURSEL,pData->pActiveTab->prev->wIndex, 0L);
- break;
-
- // rotate tab one right
- case VK_RIGHT:
- if(pData->pActiveTab && pData->pActiveTab->next)
- dwReturn = SendMessage(hWnd,TAB_SETCURSEL,pData->pActiveTab->next->wIndex, 0L);
- break;
- }
- break;
-
- case WM_SETFONT:
- {
- LPTABPAGE ptr;
-
- // store font
- SetWindowWord(hWnd, GWW_FONT,wParam);
-
- // calculate height of tabs
- pData->wTabHeight = CalcTabHeight(hWnd);
-
- // set new tab width
- SetWindowWord(hWnd,GWW_TABWIDTH,CalcTabWidth(pData));
- // update tab rects
- for(ptr = pData->lpHead; ptr != NULL; ptr = ptr->next)
- CalcTabRect(pData,ptr);
-
- // if lParam not zero, update window
- if(lParam)
- InvalidateRect(hWnd, NULL, FALSE);
-
- dwReturn = DefWindowProc(hWnd,uMsg,wParam,lParam);
- }
- break;
-
- // draw focus rect around caption of active tab when needed
- case WM_SETFOCUS:
- case WM_KILLFOCUS:
- {
- HDC hdc;
-
- hdc = GetDC(hWnd);
- if(pData->pActiveTab)
- DrawFocusRect(hdc,&pData->pActiveTab->rcCaption);
- ReleaseDC(hWnd,hdc);
- dwReturn = DefWindowProc(hWnd,uMsg,wParam,lParam);
- }
- break;
-
-
- case WM_GETFONT:
- dwReturn = GetWindowWord(hWnd,GWW_FONT);
- break;
-
- case WM_GETDLGCODE:
- dwReturn = DLGC_WANTARROWS;
- break;
-
- case WM_PAINT:
- dwReturn = OnPaint(pData);
- break;
-
- case WM_LBUTTONDOWN:
- {
- POINT pt;
-
- pt.x = LOWORD(lParam);
- pt.y = HIWORD(lParam);
-
- dwReturn = OnLButtonDown(pData, &pt);
- }
- break;
-
- case TAB_ADDTAB:
- dwReturn = OnAddTab(pData, wParam, lParam);
- break;
-
- case TAB_SETCURSEL:
- dwReturn = OnSetCurSel(pData,wParam);
- break;
-
- case TAB_GETCURSEL:
- dwReturn = pData->pActiveTab->wIndex;
- break;
-
- case TAB_GETCOUNT:
- dwReturn = pData->wNumTabs;
- break;
-
- case TAB_DELETETAB:
- dwReturn = OnDeleteTab(pData,wParam);
- break;
-
- case TAB_FINDTAB:
- dwReturn = OnFindTab(pData,(LPCSTR)lParam);
- break;
-
- case TAB_GETTEXTLEN:
- dwReturn = OnGetTextLength(pData,wParam);
- break;
-
- case TAB_GETTEXT:
- dwReturn = OnGetText(pData,wParam,(LPSTR)lParam);
- break;
-
- default:
- dwReturn = DefWindowProc(hWnd,uMsg,wParam,lParam);
- }
-
- // unlock control block
- if(uMsg != WM_NCDESTROY)
- GlobalUnlock((HGLOBAL)GetWindowWord(hWnd,0));
-
- return dwReturn;
- }
-
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: DrawBorder
- // Purpose: draw border around control
- // Parameters: hdc - device context
- // lprc - control rect
- // pData - pointer to tab control block
- // pPens - array of pens need for drawing
- //
- // Returns: n/a
- ///////////////////////////////////////////////////////////////////////////
- void WINAPI DrawBorder(HDC hdc, LPRECT lprc, LPTABCTLBLK pData, HPEN *pPens)
- {
- POINT pt[4];
- HPEN hOldPen;
- RECT rc;
-
- // copy the rect
- CopyRect(&rc,lprc);
-
- // offset top by height of tap
- rc.top += (pData->wTabHeight - 1);
-
- // now draw the u shaped frame
- hOldPen = SelectObject(hdc, pPens[PEN_BLACK]);
-
- // black frame
- pt[0].x = rc.left;
- pt[0].y = rc.top;
- pt[1].x = rc.left;
- pt[1].y = rc.bottom;
- pt[2].x = rc.right;
- pt[2].y = rc.bottom;
- pt[3].x = rc.right;
- pt[3].y = rc.top-1; // make sure they connect
-
- Polyline(hdc,(LPPOINT)&pt,4);
-
- SelectObject(hdc,pPens[PEN_WHITE]);
-
- // two white border lines
- pt[0].x = rc.left+1;
- pt[0].y = rc.top;
- pt[1].x = rc.left+1;
- pt[1].y = rc.bottom-1;
-
- Polyline(hdc,(LPPOINT)&pt,2);
-
- pt[0].x = rc.left+2;
- pt[0].y = rc.top;
- pt[1].x = rc.left+2;
- pt[1].y = rc.bottom-2;
- Polyline(hdc,(LPPOINT)&pt,2);
-
- SelectObject(hdc,pPens[PEN_SHADOW]);
-
- // two shadow lines
- pt[0].x = rc.left + 1;
- pt[0].y = rc.bottom - 1;
- pt[1].x = rc.right-1;
- pt[1].y = rc.bottom - 1;
- pt[2].x = rc.right - 1;
- pt[2].y = rc.top - 1;
-
- Polyline(hdc,(LPPOINT)&pt,3);
-
- pt[0].x = rc.left + 2;
- pt[0].y = rc.bottom - 2;
- pt[1].x = rc.right-2;
- pt[1].y = rc.bottom - 2;
- pt[2].x = rc.right - 2;
- pt[2].y = rc.top - 1;
- Polyline(hdc,(LPPOINT)&pt,3);
-
- // restore old pen
- SelectObject(hdc,hOldPen);
- }
- ///////////////////////////////////////////////////////////////////////////
- // Function: CalcTabHeight
- // Purpose: calculates height of tab based upon current system font
- // Parameters: none
- //
- // Returns: height of tab in pixels
- ///////////////////////////////////////////////////////////////////////////
- WORD WINAPI CalcTabHeight(HWND hWnd)
- {
- HDC hdc;
- TEXTMETRIC tm;
- HFONT hOldFont;
-
- hdc = GetDC(NULL);
- hOldFont = (HFONT)SelectObject(hdc,GetActiveTabFont(hWnd));
- GetTextMetrics(hdc,&tm);
- SelectObject(hdc,hOldFont);
- ReleaseDC(NULL,hdc);
-
- return tm.tmHeight + tm.tmHeight/2 + 4;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: GetActiveTabFont
- // Purpose: returns handle to font to used for active tab
- // Parameters: none
- //
- // Returns: handle to font
- ///////////////////////////////////////////////////////////////////////////
- HFONT WINAPI GetActiveTabFont(HWND hWnd)
- {
- HFONT hFont;
-
- hFont = (HFONT)GetWindowWord(hWnd,GWW_FONT);
-
- // use system font if no font stored in window
- if(!IsGDIObject(hFont))
- hFont = (HFONT)GetStockObject(SYSTEM_FONT);
-
- return hFont;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: GetDepressedTabFont
- // Purpose: returns handle to font to used for depressed tab
- // Parameters: none
- //
- // Returns: handle to font
- ///////////////////////////////////////////////////////////////////////////
- HFONT WINAPI __export GetDepressedTabFont(void)
- {
- // use system font if no depressed font created
- if(!IsGDIObject(hDepressedFont))
- return (HFONT)GetStockObject(SYSTEM_FONT);
- else
- return hDepressedFont;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: OnNCCreate
- // Purpose: responds to WM_NCCREATE
- // Parameters: hWnd - control window
- // lpcs - create struct
- //
- // Returns: return value
- ///////////////////////////////////////////////////////////////////////////
- LRESULT WINAPI OnNCCreate(HWND hWnd, CREATESTRUCT FAR *lpcs)
- {
- HGLOBAL hGlobal;
- LPTABCTLBLK pData = NULL;
-
- // allocate new block of memory for control info
- if(!(hGlobal = GlobalAlloc(GHND,sizeof(TABCTLBLK))))
- return 0L; // abort if error
-
- // store in window extra bytes
- SetWindowWord(hWnd,GWW_DATA,(WORD)hGlobal);
-
- // get a pointer to it
- pData = (LPTABCTLBLK)GlobalLock(hGlobal);
-
- // save window handle so we don't have to pass it around
- pData->hWnd = hWnd;
-
- // store style bits
- if(LOWORD(lpcs->style) & TBS_SHADOW)
- pData->bShadow = TRUE;
- else
- pData->bShadow = FALSE;
-
- // clear rest of the struct members
- pData->lpHead = pData->lpTail = NULL;
- pData->wNumTabs = 0;
-
- // calculate height of tabs
- pData->wTabHeight = CalcTabHeight(hWnd);
-
- // use default return value
- return DefWindowProc(hWnd,WM_NCCREATE,0,(LPARAM)lpcs);
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: OnPaint
- // Purpose: repsonds to WM_PAINT
- // Parameters: hWnd - window handle
- // pData - tab control block
- //
- // Returns: std return value
- ///////////////////////////////////////////////////////////////////////////
- LRESULT WINAPI OnPaint(LPTABCTLBLK pData)
- {
- HDC hdc;
- PAINTSTRUCT ps;
- RECT rc;
- HPEN pens[3];
- LPTABPAGE ptr;
- HPEN hOldPen;
-
-
- // get pens needed for drawing
- pens[PEN_WHITE] = (HPEN)GetStockObject(WHITE_PEN);
- pens[PEN_BLACK] = (HPEN)GetStockObject(BLACK_PEN);
- pens[PEN_SHADOW] = CreatePen(PS_SOLID,1,GetSysColor(COLOR_BTNSHADOW));
-
- // get bounding rect
- GetClientRect(pData->hWnd,&rc);
-
- // to keep everything inside borders
- rc.right--;
- rc.bottom--;
-
- // start painting
- hdc = BeginPaint(pData->hWnd,&ps);
-
- // draw border around control
- DrawBorder(hdc,&rc,pData,pens);
-
- // get pointer to head of tab list
- ptr = pData->lpHead;
-
- // while ptr is valid
- while(ptr)
- {
- // draw tab up if is active tab
- if(ptr == pData->pActiveTab)
- DrawUpTab(hdc,pData,ptr,pens);
- else
- DrawDownTab(hdc,pData,ptr,pens);
-
- // draw caption
- DrawTabText(hdc,pData,ptr);
-
- // get pointer to next tab in list
- ptr = ptr->next;
- }
-
- // fill in horizontal lines
-
- // if first tab isn't the active tab...
- if(pData->pActiveTab->wIndex != 0)
- {
- hOldPen = (HPEN)SelectObject(hdc,pens[PEN_BLACK]);
- MoveTo(hdc,rc.left,pData->wTabHeight - 2);
- LineTo(hdc, pData->pActiveTab->rcTab.left,pData->wTabHeight - 2);
-
- SelectObject(hdc,pens[PEN_WHITE]);
- MoveTo(hdc,rc.left + 1,pData->wTabHeight - 1);
- LineTo(hdc, pData->pActiveTab->rcTab.left + 1,pData->wTabHeight - 1);
-
- MoveTo(hdc,rc.left + 1,pData->wTabHeight);
- LineTo(hdc, pData->pActiveTab->rcTab.left + 1,pData->wTabHeight);
-
- SelectObject(hdc,hOldPen);
- }
-
- // if edge of last tab is less than the edge of the control...
- if(pData->pActiveTab->rcTab.right < rc.right)
- {
- hOldPen = (HPEN)SelectObject(hdc,pens[PEN_BLACK]);
- MoveTo(hdc,pData->pActiveTab->rcTab.right,pData->wTabHeight - 2);
- LineTo(hdc, rc.right + 1,pData->wTabHeight - 2);
-
- SelectObject(hdc,pens[PEN_WHITE]);
- MoveTo(hdc,pData->pActiveTab->rcTab.right,pData->wTabHeight - 1);
- LineTo(hdc, rc.right,pData->wTabHeight - 1);
-
- MoveTo(hdc,pData->pActiveTab->rcTab.right - 1,pData->wTabHeight);
- LineTo(hdc, rc.right - 1,pData->wTabHeight);
-
- SelectObject(hdc,hOldPen);
- }
-
- // cleanup
- EndPaint(pData->hWnd,&ps);
- DeleteObject(pens[PEN_SHADOW]);
-
- return 0L;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: OnAddTab
- // Purpose: responds to TAB_ADDTAB, adds new tab to control
- // Parameters: pData - pointer to tab control block
- // wParam, lParam - callback parameters
- //
- // Returns: TRUE - on success
- // FALSE - on failure
- ///////////////////////////////////////////////////////////////////////////
- LRESULT WINAPI OnAddTab(LPTABCTLBLK pData, WPARAM wParam, LPARAM lParam)
- {
- LPDLGTEMPLATE lpDlgTemplate;
- HRSRC hrsrcDialog;
- HGLOBAL hGlblDlgTemplate;
- BOOL bResult;
- int index;
-
- // trivial abort
- if(!lParam)
- return FALSE;
-
-
- if(wParam) // must be hInstance of module to load template from
- {
- hrsrcDialog = FindResource((HINSTANCE)wParam, (LPCSTR)lParam, RT_DIALOG);
- if (hrsrcDialog == NULL)
- return FALSE;
-
- hGlblDlgTemplate = LoadResource((HINSTANCE)wParam, hrsrcDialog);
- lpDlgTemplate = (LPDLGTEMPLATE) LockResource(hGlblDlgTemplate);
- if (lpDlgTemplate == NULL)
- return(FALSE);
- }
- else // user passed a handle to an in-memory dialog template
- { // just lock it down
- lpDlgTemplate = (LPDLGTEMPLATE)GlobalLock((HGLOBAL)lParam);
- if(lpDlgTemplate == NULL)
- return FALSE;
- }
-
- // go ahead and create tab
- if( (index = CreateNewTab(pData,lpDlgTemplate)) == -1)
- bResult = FALSE;
- else
- bResult = TRUE;
-
- // set current selection to new tab
- SendMessage(pData->hWnd,TAB_SETCURSEL,(WPARAM)index,0L);
-
- // free template if we loaded it
- if(wParam)
- {
- UnlockResource(hGlblDlgTemplate);
- FreeResource(hGlblDlgTemplate);
- }
-
- return bResult;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: CreateNewTab
- // Purpose: builds new tab from template
- // Parameters: pData - pointer to tab control block
- // lpDlgTemplate - pointer to dlg template
- //
- // Returns: index - on sucess
- // -1 - on failure
- ///////////////////////////////////////////////////////////////////////////
- int WINAPI __export CreateNewTab(LPTABCTLBLK pData,LPDLGTEMPLATE lpDlgTemplate)
- {
- LPTABPAGE pTabPage = NULL;
- LPTABPAGE ptr;
-
- // alloc room for page
- pTabPage = (LPTABPAGE)malloc(sizeof(TABPAGE));
-
- // abort
- if(pTabPage == NULL)
- return -1;
-
- // clear
- memset(pTabPage,0,sizeof(TABPAGE));
-
- // create the controls that belong to tab
- if(!CreateTabControls(pData,pTabPage,lpDlgTemplate))
- {
- FreeTab(pTabPage);
- return -1;
- }
-
- // if this is the first tab created...
- if(pData->lpHead == NULL)
- {
- pData->lpHead = pData->lpTail = pTabPage;
- pTabPage->next = pTabPage->prev = NULL;
- }
- else // append to end of list
- {
- pData->lpTail->next = pTabPage;
- pTabPage->prev = pData->lpTail;
- pTabPage->next = NULL;
- pData->lpTail = pTabPage;
- }
-
- // set index
- pTabPage->wIndex = pData->wNumTabs;
-
- // increment number of tabs
- pData->wNumTabs++;
-
- // set new tab width
- SetWindowWord(pData->hWnd,GWW_TABWIDTH,CalcTabWidth(pData));
-
- // update tab rects
- for(ptr = pData->lpHead; ptr != NULL; ptr = ptr->next)
- CalcTabRect(pData,ptr);
-
- // return index to tab
- return pTabPage->wIndex;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: AppendControlToTab
- // Purpose: adds new control to list of controls in tab
- // Parameters: pTab - pointer to tab
- // nID - id of control to add to list
- //
- // Returns: TRUE - on sucess
- // FALSE - on failure
- ///////////////////////////////////////////////////////////////////////////
- BOOL WINAPI __export AppendControlToTab(LPTABPAGE pTab, WORD nID)
- {
- LPTABCHILDCTL pControl;
- LPTABCHILDCTL ptr;
-
- pControl = (LPTABCHILDCTL)malloc(sizeof(TABCHILDCTL));
- if(pControl == NULL)
- return FALSE;
-
- pControl->wID = nID;
- pControl->next = NULL;
-
- if(pTab->lpControls == NULL)
- pTab->lpControls = pControl;
- else
- {
- ptr = pTab->lpControls;
- while(ptr->next != NULL)
- ptr = ptr->next;
-
- ptr->next = pControl;
- }
-
- return TRUE;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: CreateTabControls
- // Purpose: creates each control in template and adds to tab's list of
- // controls
- // Parameters: pData - pointer tab control block
- // pTab - pointer to tab
- // lpDlgTemplate - pointer to dlg template
- //
- // Returns: TRUE - on sucess
- // FALSE - on failure
- ///////////////////////////////////////////////////////////////////////////
- BOOL WINAPI __export CreateTabControls(LPTABCTLBLK pData, LPTABPAGE pTab, LPDLGTEMPLATE lpDlgTemplate)
- {
- HWND hWndPrevChild;
- HWND hDlg;
- HFONT hFont;
- LPBYTE p, lpszClass, lpszText, lpCreateParams;
- LPFONTINFO lpFontInfo;
- HWND hWndChild;
- BYTE bNumControls;
- LPDLGITEMTEMPLATE lpDlgItemTemplate;
- RECT rc;
- int length;
-
- hDlg = GetParent(pData->hWnd);
- hWndPrevChild = GetWindow(hDlg,GW_CHILD);
-
- hFont = GetWindowFont(hDlg);
-
- // Ignore everything in Dialog Template except for the number
- // of controls.
- bNumControls = lpDlgTemplate->dtItemCount;
-
- p = (LPBYTE) (&lpDlgTemplate->dtCY + 1); // Start of Menu name
- while (*p++ != 0) ; // Skip the menu name string
-
- // p should pointer to caption
- length = lstrlen(p);
- pTab->szCaption = (char *)malloc(length + 1);
- if(pTab->szCaption)
- lstrcpy(pTab->szCaption,p);
-
- while (*p++ != 0) ; // Skip the Class name string
-
- while (*p++ != 0) ; // Skip the Caption string
-
- lpFontInfo = (LPFONTINFO) p; // Start of FONTINFO (if exists)
-
- // Find address of first DLGITEMTEMPLATE structure
- if (lpDlgTemplate->dtStyle & DS_SETFONT) {
- p = (LPBYTE) (&lpFontInfo->PointSize + 1);
- while (*p++ != 0) ; // Skip the Type face name string
- lpDlgItemTemplate = (LPDLGITEMTEMPLATE) p;
- } else lpDlgItemTemplate = (LPDLGITEMTEMPLATE) lpFontInfo;
-
- // Create all of the child controls
- while (bNumControls-- != 0) {
-
- lpszClass = (LPBYTE) (&lpDlgItemTemplate->dtilStyle + 1);
- if (*lpszClass & PREDEFINEDCNTRLBIT) {
- lpszText = lpszClass + 1;
- lpszClass = (LPBYTE) szPredefinedClassNames
- [(WORD)(*lpszClass) - PREDEFINEDCNTRLBIT];
- } else for (lpszText = lpszClass; *lpszText++ != 0; ) ;
-
- // Find address of number-of-bytes-in-additional-data
- for (lpCreateParams = lpszText; *lpCreateParams++ != 0; ) ;
-
- if (lpDlgItemTemplate->dtilID == (int)GetWindowWord(pData->hWnd,GWW_ID))
- goto NextControl;
-
- /* add control to list in tab */
-
- // give control unique id if -1
- if(lpDlgItemTemplate->dtilID == (WORD)-1)
- {
- pData->wStaticCount++;
- lpDlgItemTemplate->dtilID = ((WORD)-1) - pData->wStaticCount;
- }
-
- if(!AppendControlToTab(pTab,lpDlgItemTemplate->dtilID))
- return FALSE;
-
- SetRect(&rc, lpDlgItemTemplate->dtilX,
- lpDlgItemTemplate->dtilY,
- lpDlgItemTemplate->dtilX + lpDlgItemTemplate->dtilCX,
- lpDlgItemTemplate->dtilY + lpDlgItemTemplate->dtilCY);
- MapDialogRect(hDlg, &rc);
-
- hWndChild = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
- (LPCSTR) lpszClass, (LPCSTR) lpszText,
- lpDlgItemTemplate->dtilStyle,
- rc.left, rc.top,
- rc.right - rc.left, rc.bottom - rc.top,
- hDlg, (HMENU) lpDlgItemTemplate->dtilID,
- (HINSTANCE)GetWindowWord(pData->hWnd,GWW_HINSTANCE),
- lpCreateParams + 1); // +1 to point to 1st byte of data
-
- if (hWndChild == NULL)
- return(FALSE);
-
- // Tell the new control to use the same font as dialog box
- SetWindowFont(hWndChild, hFont, FALSE);
-
- // Fix the Z-Order of the controls
- SetWindowPos(hWndChild, hWndPrevChild, 0, 0, 0, 0,
- SWP_NOMOVE | SWP_NOSIZE);
-
- hWndPrevChild = hWndChild;
-
- NextControl:
- // Point to the next DlgItemTemplate
- lpDlgItemTemplate = (LPDLGITEMTEMPLATE)
- (lpCreateParams + 1 + *lpCreateParams);
- }
-
- return TRUE;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: FreeTab
- // Purpose: frees memory associated with tab
- // note that pointer is no longer valid
- // Parameters: pTab - pointer to tab to free
- //
- // Returns: n/a
- ///////////////////////////////////////////////////////////////////////////
- void WINAPI FreeTab(LPTABPAGE pTab)
- {
- LPTABCHILDCTL ptr;
- LPTABCHILDCTL prev;
-
- prev = pTab->lpControls;
- while(prev != NULL)
- {
- ptr = prev->next;
- free(prev);
- prev = ptr;
- }
-
- free(pTab->szCaption);
- free(pTab);
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: OnNCDestroy
- // Purpose: responds to WM_NCDESTROY
- // Parameters: pData - tab control block
- //
- // Returns: std result
- ///////////////////////////////////////////////////////////////////////////
- LRESULT WINAPI OnNCDestroy(LPTABCTLBLK pData)
- {
- LPTABPAGE ptr;
- LPTABPAGE prev;
- HWND hWnd;
-
- prev = pData->lpHead;
- while(prev != NULL)
- {
- ptr = prev->next;
- FreeTab(prev);
- prev = ptr;
- }
-
-
- hWnd = pData->hWnd;
-
- GlobalUnlock((HGLOBAL)GetWindowWord(hWnd,0));
- GlobalFree((HGLOBAL)GetWindowWord(hWnd,0));
- SetWindowWord(hWnd,GWW_DATA,0);
-
- // use default return value
- return DefWindowProc(hWnd,WM_NCDESTROY,0,0L);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: GetTabPtrByIndex
- // Purpose: returns pointer to tab based upon index
- // Parameters: pData - pointer to tab control block
- // wIndex - index of tab to find
- //
- // Returns: pointer to tab - on success
- // NULL - on failure
- ///////////////////////////////////////////////////////////////////////////
- LPTABPAGE WINAPI GetTabPtrByIndex(LPTABCTLBLK pData, WORD wIndex)
- {
- LPTABPAGE pTab;
-
- pTab = pData->lpHead;
- while(pTab)
- {
- if(pTab->wIndex == wIndex)
- return pTab;
-
- pTab = pTab->next;
- }
-
- return NULL;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: OnSetCurSel
- // Purpose: responds to TAB_SETCURSEL
- // Parameters: pData - pointer to tab control block
- // wIndex - index of tab to set
- //
- // Returns: std return value
- ///////////////////////////////////////////////////////////////////////////
- LRESULT WINAPI OnSetCurSel(LPTABCTLBLK pData, WORD wIndex)
- {
- LPTABPAGE pTab;
- UINT uFlags;
- LPTABCHILDCTL ptr;
- HWND hDlg;
- RECT rc;
-
- uFlags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE |
- SWP_NOZORDER;
-
-
- hDlg = GetParent(pData->hWnd);
-
- pTab = GetTabPtrByIndex(pData,wIndex);
- if(pTab)
- {
- // hide controls of current top tab
- if(pData->pActiveTab)
- {
- ptr = pData->pActiveTab->lpControls;
-
- while(ptr)
- {
- SetWindowPos(GetDlgItem(hDlg,ptr->wID),NULL,0,0,0,0,
- uFlags | SWP_HIDEWINDOW);
-
- ptr = ptr->next;
- }
-
- // update area of tab
- CopyRect(&rc, &pData->pActiveTab->rcTab);
- rc.bottom += 3;
- MapWindowPoints(pData->hWnd,hDlg,(POINT FAR *)&rc,2);
- InvalidateRect(hDlg,&rc,TRUE);
- }
-
- // show controls of new tab
- ptr = pTab->lpControls;
- while(ptr)
- {
- SetWindowPos(GetDlgItem(hDlg,ptr->wID),NULL,0,0,0,0,
- uFlags | SWP_SHOWWINDOW);
-
- ptr = ptr->next;
- }
-
- // store pointer to active tab
- pData->pActiveTab = pTab;
-
- // update area of tab
- CopyRect(&rc, &pData->pActiveTab->rcTab);
- rc.bottom += 3;
- MapWindowPoints(pData->hWnd,hDlg,(POINT FAR *)&rc,2);
- InvalidateRect(hDlg,&rc,TRUE);
- }
- else
- return FALSE;
-
- // let parent know that tab has changed
- NotifyParent(pData->hWnd, TABN_CHANGETAB) ;
-
- return (LRESULT)TRUE;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: CalcTabRect
- // Purpose: calculates rectangle of top part of tab
- // Parameters: pData - pointer to tab control block
- // pTabPage - pointer to tab page
- //
- // Returns: n/a
- ///////////////////////////////////////////////////////////////////////////
- void WINAPI CalcTabRect(LPTABCTLBLK pData,LPTABPAGE pTabPage)
- {
- WORD nTabWidth = GetWindowWord(pData->hWnd,GWW_TABWIDTH);
- HFONT hFont, hOldFont;
- HDC hdc;
- DWORD dwExtents;
- WORD nMaxWidth = 0;
-
- // get size of tab
- hFont = (HFONT)SendMessage(pData->hWnd,WM_GETFONT,0,0L);
- hdc = GetDC(NULL);
- hOldFont = (HFONT)SelectObject(hdc,hFont);
-
- dwExtents = GetTextExtent(hdc, pTabPage->szCaption, lstrlen(pTabPage->szCaption));
-
- SelectObject(hdc,hOldFont);
- ReleaseDC(NULL,hdc);
-
- if(pTabPage->prev == NULL)
- pTabPage->rcTab.left = 0;
- else
- pTabPage->rcTab.left = pTabPage->prev->rcTab.right + 1;
-
- pTabPage->rcTab.top = 0;
- pTabPage->rcTab.bottom = pData->wTabHeight;
-
- pTabPage->rcTab.right = pTabPage->rcTab.left + nTabWidth;
-
- pTabPage->rcCaption.left = 0;
- pTabPage->rcCaption.top = 0;
- pTabPage->rcCaption.right = LOWORD(dwExtents) + 4;
- pTabPage->rcCaption.bottom = HIWORD(dwExtents) + 4;
-
- OffsetRect(&pTabPage->rcCaption,
- pTabPage->rcTab.left + ((pTabPage->rcTab.right - pTabPage->rcTab.left) - (pTabPage->rcCaption.right - pTabPage->rcCaption.left))/2,
- ((pTabPage->rcTab.bottom - pTabPage->rcTab.top) - (pTabPage->rcCaption.bottom - pTabPage->rcCaption.top))/2);
-
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: DrawUpTab
- // Purpose: draws tab in up position
- // Parameters: hdc - device context to draw on
- // pData - pointer to tab control block
- // pTabPage - ponter to tab page
- //
- // Returns: n/a
- ///////////////////////////////////////////////////////////////////////////
- void WINAPI DrawUpTab(HDC hdc, LPTABCTLBLK pData,LPTABPAGE pTabPage, HPEN *pPens)
- {
- POINT pt[6];
- HPEN hOldPen;
- LPRECT lprc;
-
- // up tab is down tab with a few more lines around the inside of tab
- DrawDownTab(hdc,pData,pTabPage,pPens);
-
- lprc = &pTabPage->rcTab;
-
- hOldPen = SelectObject(hdc,pPens[PEN_WHITE]);
-
- pt[0].x = lprc->left + 2;
- pt[0].y = lprc->bottom;
-
- pt[1].x = lprc->left + 2;
- pt[1].y = lprc->top + 4;
-
- pt[2].x = lprc->left + 4;
- pt[2].y = lprc->top + 2;
-
- pt[3].x = lprc->right - 4;
- pt[3].y = lprc->top + 2;
-
- Polyline(hdc,(LPPOINT)&pt,4);
-
- pt[0].x = lprc->left + 3;
- pt[0].y = lprc->top + 4;
-
- pt[1].x = lprc->left + 5;
- pt[1].y = lprc->top + 2;
-
- Polyline(hdc,(LPPOINT)&pt,2);
-
- SelectObject(hdc,pPens[PEN_SHADOW]);
-
- pt[0].x = lprc->right - 4 ;
- pt[0].y = lprc->top + 2;
-
- pt[1].x = lprc->right - 2;
- pt[1].y = lprc->top + 4;
-
- pt[2].x = lprc->right - 2;
- pt[2].y = lprc->bottom + 1;
-
- Polyline(hdc,(LPPOINT)&pt,3);
-
- pt[0].x = lprc->right - 4 ;
- pt[0].y = lprc->top + 3;
-
- pt[1].x = lprc->right - 2 ;
- pt[1].y = lprc->top + 5;
-
- Polyline(hdc,(LPPOINT)&pt,2);
-
- SelectObject(hdc,hOldPen);
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: DrawDownTab
- // Purpose: draws tab in down position
- // Parameters: hdc - device context to draw on
- // pData - pointer to tab control block
- // pTabPage - ponter to tab page
- //
- // Returns: n/a
- ///////////////////////////////////////////////////////////////////////////
- void WINAPI DrawDownTab(HDC hdc, LPTABCTLBLK pData,LPTABPAGE pTabPage, HPEN *pPens)
- {
- POINT pt[6];
- HPEN hOldPen;
- LPRECT lprc;
-
- lprc = &pTabPage->rcTab;
-
- hOldPen = SelectObject(hdc,pPens[PEN_BLACK]);
-
- pt[0].x = lprc->left;
- //pt[0].y = lprc->bottom;
- pt[0].y = lprc->bottom - 2;
-
- pt[1].x = lprc->left;
- pt[1].y = lprc->top + 4;
-
- pt[2].x = lprc->left + 4;
- pt[2].y = lprc->top;
-
- pt[3].x = lprc->right - 4;
- pt[3].y = lprc->top;
-
- pt[4].x = lprc->right;
- pt[4].y = lprc->top + 4;
-
- pt[5].x = lprc->right;
- pt[5].y = lprc->bottom;
-
- Polyline(hdc,(LPPOINT)&pt,6);
-
- SelectObject(hdc,pPens[PEN_WHITE]);
-
- pt[0].x = lprc->left + 1;
- pt[0].y = lprc->bottom;
-
- pt[1].x = lprc->left + 1;
- pt[1].y = lprc->top + 4;
-
- pt[2].x = lprc->left + 4;
- pt[2].y = lprc->top + 1;
-
- pt[3].x = lprc->right - 3;
- pt[3].y = lprc->top + 1;
-
- Polyline(hdc,(LPPOINT)&pt,4);
-
- SelectObject(hdc,pPens[PEN_SHADOW]);
-
- pt[0].x = lprc->right - 3 ;
- pt[0].y = lprc->top + 2;
-
- pt[1].x = lprc->right - 1;
- pt[1].y = lprc->top + 4;
-
- pt[2].x = lprc->right - 1;
- pt[2].y = lprc->bottom + 1;
-
- Polyline(hdc,(LPPOINT)&pt,3);
-
- SelectObject(hdc, hOldPen);
- }
-
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: OnLButtonDown
- // Purpose: responds to WM_LBUTTONDOWN
- // Parameters: pData - pointer to tab control block
- // x,y - coordinate of click
- //
- // Returns: 0
- ///////////////////////////////////////////////////////////////////////////
- LRESULT OnLButtonDown(LPTABCTLBLK pData, POINT *lpPt)
- {
- LPTABPAGE ptr;
-
- SetFocus(pData->hWnd);
-
- if(lpPt->y > (int)pData->wTabHeight)
- return 0L;
-
- ptr = pData->lpHead;
- while(ptr)
- {
- if(PtInRect(&ptr->rcTab,*lpPt))
- {
- if(pData->pActiveTab != ptr)
- SendMessage(pData->hWnd,TAB_SETCURSEL,ptr->wIndex,0L);
- return 0L;
- }
- ptr = ptr->next;
- }
- return 0L;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: DrawTabText
- // Purpose: draw caption text
- // Parameters: hdc - device context
- // pData - pointer to tab control block
- // pTabPage - pointer to tab page
- //
- // Returns: n/a
- ///////////////////////////////////////////////////////////////////////////
- void WINAPI DrawTabText(HDC hdc, LPTABCTLBLK pData,LPTABPAGE pTabPage)
- {
- int bk_mode;
- HFONT hOldFont;
- COLORREF cwOld;
-
- bk_mode = SetBkMode(hdc,TRANSPARENT);
- if(pData->pActiveTab == pTabPage)
- {
- hOldFont = (HFONT)SelectObject(hdc,GetActiveTabFont(pData->hWnd));
- if(GetFocus() == pData->hWnd)
- DrawFocusRect(hdc,&pData->pActiveTab->rcCaption);
- }
- else
- hOldFont = (HFONT)SelectObject(hdc,GetDepressedTabFont());
-
- /* draw white text to give chisled look */
- cwOld = SetTextColor(hdc,RGB(0xFF,0xFF,0xFF));
-
- if(pData->bShadow)
- {
- OffsetRect(&pTabPage->rcCaption,1,1);
- DrawText(hdc,pTabPage->szCaption,lstrlen(pTabPage->szCaption),&pTabPage->rcCaption,
- DT_CENTER | DT_VCENTER | DT_SINGLELINE);
- /* shift up and to the left */
- OffsetRect(&pTabPage->rcCaption,-1,-1);
- }
-
- /* use black text */
- SetTextColor(hdc,RGB(0x00,0x00,0x00));
-
- DrawText(hdc,pTabPage->szCaption,lstrlen(pTabPage->szCaption),&pTabPage->rcCaption,
- DT_CENTER | DT_VCENTER | DT_SINGLELINE);
-
- /* restore old text color */
- SetTextColor(hdc,cwOld);
-
- SelectObject(hdc,hOldFont);
- SetBkMode(hdc,bk_mode);
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: NotifyParent
- // Purpose: sends notification message to parent
- // Parameters: hWndControl - window handle of control
- // wNotifyCode - notification code
- //
- // Returns: return value from parent
- ///////////////////////////////////////////////////////////////////////////
- LRESULT WINAPI NotifyParent(HWND hWndControl, WORD wNotifyCode)
- {
- LRESULT lResult;
-
- lResult = SendMessage(GetParent(hWndControl), WM_COMMAND,
- GetWindowWord(hWndControl, GWW_ID),
- MAKELPARAM(hWndControl, wNotifyCode));
- return(lResult);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: OnDeleteTab
- // Purpose: deletes tab from list of tabs
- // Parameters: pData - pointer to tab control block
- // wIndex - index of tab to delete
- //
- // Returns: TRUE,FALSE
- ///////////////////////////////////////////////////////////////////////////
- LRESULT WINAPI OnDeleteTab(LPTABCTLBLK pData,WORD wIndex)
- {
- LPTABPAGE ptr;
- RECT rc;
- HWND hDlg;
-
- ptr = GetTabByIndex(pData,wIndex);
- if(!ptr)
- return FALSE;
-
- if(ptr->prev)
- ptr->prev->next = ptr->next;
-
- if(ptr->next)
- ptr->next->prev = ptr->prev;
-
- if(pData->lpHead == ptr)
- pData->lpHead = ptr->next;
-
-
- if(pData->lpTail == ptr)
- pData->lpTail = ptr->prev;
-
- if(pData->pActiveTab == ptr)
- pData->pActiveTab = (ptr->next?ptr->next:ptr->prev);
-
- hDlg = GetParent(pData->hWnd);
- GetClientRect(pData->hWnd,&rc);
- InflateRect(&rc,-3,-3);
- MapWindowPoints(pData->hWnd,hDlg,(POINT FAR *)&rc,2);
- InvalidateRect(hDlg,&rc,TRUE);
-
- FreeTab(ptr);
-
- return TRUE;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: OnFindTab
- // Purpose: returns index of tab with caption lpBuffer
- // Parameters: pData - pointer to tab control block
- // lpBuffer - text to match
- //
- // Returns: index on success
- // -1 on failure
- ///////////////////////////////////////////////////////////////////////////
- LRESULT WINAPI OnFindTab(LPTABCTLBLK pData,LPCSTR lpBuffer)
- {
- LPTABPAGE ptr;
-
- ptr = pData->lpHead;
-
- while(ptr)
- {
- if(lstrcmpi(lpBuffer,ptr->szCaption) == 0)
- return ptr->wIndex;
- ptr = ptr->next;
-
- }
- return (LRESULT)-1;
-
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: OnGetTextLength
- // Purpose: get length of caption of tab wIndex
- // Parameters: pData - pointer to tab control block
- // wIndex - index of tab
- //
- // Returns: length of tab or zero on failure
- ///////////////////////////////////////////////////////////////////////////
- LRESULT WINAPI OnGetTextLength(LPTABCTLBLK pData,WORD wIndex)
- {
- LPTABPAGE ptr;
-
- ptr = GetTabByIndex(pData,wIndex);
- if(ptr)
- return lstrlen(ptr->szCaption);
-
- return 0L;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: OnGetText
- // Purpose: copy text of tab into buffer
- // Parameters: pData - pointer to tab control block
- // wIndex - index of tab
- // lpBuffer - buffer to copy text to
- //
- // Returns: TRUE/FALSE
- ///////////////////////////////////////////////////////////////////////////
- LRESULT WINAPI OnGetText(LPTABCTLBLK pData,WORD wIndex,LPSTR lpBuffer)
- {
- LPTABPAGE ptr;
-
- ptr = GetTabByIndex(pData,wIndex);
-
- if(ptr)
- {
- lstrcpy(lpBuffer,ptr->szCaption);
- return TRUE;
- }
- return FALSE;
- }
-
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Function: GetTabByIndex
- // Purpose: returns pointer to tab with index of wIndex
- // Parameters: pData - pointer to tab control block
- // wIndex - index of tab to find
- //
- // Returns: NULL or pointer to tab
- ///////////////////////////////////////////////////////////////////////////
- LPTABPAGE GetTabByIndex(LPTABCTLBLK pData,WORD wIndex)
- {
- LPTABPAGE ptr;
-
- ptr = pData->lpHead;
-
- while(ptr)
- {
- if(ptr->wIndex == wIndex)
- return ptr;
- ptr = ptr->next;
-
- }
- return NULL;
- }
-
-
- WORD CalcTabWidth(LPTABCTLBLK pData)
- {
- LPTABPAGE ptr;
- HFONT hFont, hOldFont;
- HDC hdc;
- DWORD dwExtents;
- WORD nMaxWidth = 0;
-
- // get size of tab
- hFont = (HFONT)SendMessage(pData->hWnd,WM_GETFONT,0,0L);
- hdc = GetDC(NULL);
- hOldFont = (HFONT)SelectObject(hdc,hFont);
-
- for(ptr = pData->lpHead; ptr != NULL; ptr = ptr->next)
- {
- dwExtents = GetTextExtent(hdc, ptr->szCaption, lstrlen(ptr->szCaption));
- if(LOWORD(dwExtents) > nMaxWidth)
- nMaxWidth = LOWORD(dwExtents);
- }
-
- SelectObject(hdc,hOldFont);
- ReleaseDC(NULL,hdc);
-
- nMaxWidth += (2*WIDTH_FUDGE + 4);
-
- return nMaxWidth;
- }